import * as fs from 'node:fs'
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { createObjectCsvStringifier } from 'csv-writer'
import { format } from 'date-fns'
import { Redis } from 'ioredis'
import { Repository, DataSource } from 'typeorm'

import { InjectRedis } from '~/common/decorators/inject-redis.decorator'
import { RedisKeys } from '~/constants/cache.constant'
import { CreateUserDto } from './dto/create-user.dto'
import { QueryUserDto } from './dto/query-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
import { CUserEntity } from './entities/user.entity'
import { CUserHistoryEntity } from './entities/user-history.entity'
// eslint-disable-next-line ts/no-require-imports
import csv = require('csv-parser')

// 定义文件接口，适配Fastify的文件对象
interface FileUpload {
  path: string
  originalname: string
  mimetype: string
}

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(CUserEntity)
    private readonly userRepository: Repository<CUserEntity>,
    @InjectRepository(CUserHistoryEntity)
    private readonly userHistoryRepository: Repository<CUserHistoryEntity>,
    @InjectRedis() private readonly redis: Redis,
    private dataSource: DataSource,
  ) {}

  /**
   * 生成用户ID
   * 格式：年月日 + 4位序号
   */
  async generateUserId(): Promise<string> {
    const dateStr = format(new Date(), 'yyyyMMdd')
    const key = `${RedisKeys.USER_ID_SEQ}${dateStr}`

    // 使用Redis自增获取序号
    const seq = await this.redis.incr(key)

    // 设置过期时间（2天后过期）
    await this.redis.expire(key, 60 * 60 * 24 * 2)

    // 格式化序号为4位数，不足前面补0
    const seqStr = seq.toString().padStart(4, '0')

    return `${dateStr}${seqStr}`
  }

  async create(createUserDto: CreateUserDto): Promise<CUserEntity> {
    // 检查手机号是否已存在
    const existingUser = await this.userRepository.findOne({
      where: { phone: createUserDto.phone },
    })
    if (existingUser) {
      if (existingUser.isDelete === 1) {
        existingUser.isDelete = 0
        const updatedUser = Object.assign(existingUser, createUserDto)
        return this.userRepository.save(updatedUser)
      }
      throw new BadRequestException('Phone number already exists')
    }

    // 如果没有提供userId，则生成一个新的
    if (!createUserDto.userId) {
      createUserDto.userId = await this.generateUserId()
    }

    const user = this.userRepository.create(createUserDto)
    return this.userRepository.save(user)
  }

  async findAll(queryDto: QueryUserDto) {
    const { page = 1, pageSize = 10, userName, phone, status, grade, province, city } = queryDto

    const queryBuilder = this.userRepository.createQueryBuilder('user')
      .where('user.is_delete = :isDelete', { isDelete: 0 })

    if (userName) {
      queryBuilder.andWhere('user.userName LIKE :userName', { userName: `%${userName}%` })
    }

    if (phone) {
      queryBuilder.andWhere('user.phone LIKE :phone', { phone: `%${phone}%` })
    }

    if (province) {
      queryBuilder.andWhere('user.province LIKE :province', { province: `%${province}%` })
    }

    if (city) {
      queryBuilder.andWhere('user.city LIKE :city', { city: `%${city}%` })
    }

    if (status) {
      queryBuilder.andWhere('user.status = :status', { status })
    }

    if (grade) {
      queryBuilder.andWhere('user.grade = :grade', { grade })
    }

    const total = await queryBuilder.getCount()

    const users = await queryBuilder
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .orderBy('user.createdAt', 'DESC')
      .getMany()

    return {
      items: users,
      meta: {
        total,
        page,
        pageSize,
      },
    }
  }

  async findOne(id: number): Promise<CUserEntity> {
    const user = await this.userRepository.findOne({
      where: { id, isDelete: 0 },
    })

    if (!user) {
      throw new NotFoundException(`User with ID ${id} not found`)
    }

    return user
  }

  async update(id: number, updateUserDto: UpdateUserDto): Promise<CUserEntity> {
    const user = await this.findOne(id)

    // 检查手机号是否与其他用户重复
    if (updateUserDto.phone) {
      const existingUser = await this.userRepository.findOne({
        where: { phone: updateUserDto.phone },
      })

      if (existingUser && existingUser.id !== id) {
        throw new BadRequestException('Phone number already exists')
      }
    }

    // 创建历史记录
    if (updateUserDto.status !== undefined || updateUserDto.mark !== undefined) {
      const history = new CUserHistoryEntity()
      history.userId = id
      history.editorId = updateUserDto.updateBy || 0
      
      // 获取编辑者姓名
      if (history.editorId) {
        try {
          const editor = await this.dataSource.query(
            'SELECT nickname FROM sys_user WHERE id = ?',
            [history.editorId]
          )
          if (editor && editor.length > 0) {
            history.editorName = editor[0].nickname || ''
          }
        } catch (error) {
          // 忽略错误，继续执行
          console.error('获取编辑者信息失败', error)
        }
      }
      
      // 记录状态变更
      history.statusBefore = user.status
      history.statusAfter = updateUserDto.status !== undefined ? updateUserDto.status : user.status
      
      // 记录备注变更
      history.markBefore = user.mark
      history.markAfter = updateUserDto.mark !== undefined ? updateUserDto.mark : user.mark

      // 记录其他修改内容摘要
      const changes = []
      for (const key in updateUserDto) {
        if (key !== 'status' && key !== 'mark' && key !== 'updateBy' && updateUserDto[key] !== undefined) {
          changes.push(`${key}: ${user[key]} => ${updateUserDto[key]}`)
        }
      }
      history.changes = changes.length > 0 ? changes.join('\n') : null

      // 保存历史记录
      await this.userHistoryRepository.save(history)
    }

    const updatedUser = Object.assign(user, updateUserDto)
    return this.userRepository.save(updatedUser)
  }

  async remove(id: number): Promise<CUserEntity> {
    const user = await this.findOne(id)
    user.isDelete = 1
    const updateUser = await this.userRepository.save(user)
    console.log('===>updateUser', updateUser)
    return updateUser
  }

  async importUsers(file: FileUpload, currentUserId: number): Promise<{ success: number, failed: number, errors: string[] }> {
    return new Promise((resolve, reject) => {
      const results = []
      const errors = []
      let success = 0
      let failed = 0

      fs.createReadStream(file.path)
        .pipe(csv())
        .on('data', data => results.push(data))
        .on('end', async () => {
          try {
            // 删除临时文件
            fs.unlinkSync(file.path)

            for (const row of results) {
              try {
                // 生成或使用已有的userId
                const userId = row.userId || await this.generateUserId()

                // 转换CSV行为用户DTO
                const userDto: CreateUserDto = {
                  userId,
                  phone: row.phone,
                  userName: row.userName,
                  guarder: row.guarder,
                  guarderPhone: row.guarderPhone,
                  guarderRelation: row.guarderRelation,
                  birthday: row.birthday ? new Date(row.birthday) : null,
                  school: row.school,
                  province: row.province,
                  city: row.city,
                  grade: Number.parseInt(row.grade) || 0,
                  from: Number.parseInt(row.from) || 1,
                  status: Number.parseInt(row.status) || 1,
                  mark: row.mark || '',
                  createBy: currentUserId,
                  updateBy: currentUserId,
                }

                // 验证必填字段
                if (!userDto.phone || !userDto.userName) {
                  throw new Error('Phone and userName are required')
                }

                // 检查手机号是否已存在
                const existingUser = await this.userRepository.findOne({
                  where: { phone: userDto.phone },
                })

                if (existingUser) {
                  throw new Error(`Phone number ${userDto.phone} already exists`)
                }

                const user = this.userRepository.create(userDto)
                await this.userRepository.save(user)
                success++
              }
              catch (error) {
                failed++
                errors.push(`Row ${results.indexOf(row) + 1}: ${error.message}`)
              }
            }

            resolve({ success, failed, errors })
          }
          catch (error) {
            reject(error)
          }
        })
        .on('error', (error) => {
          // 删除临时文件
          if (fs.existsSync(file.path)) {
            fs.unlinkSync(file.path)
          }
          reject(error)
        })
    })
  }

  async exportUsers(queryDto: QueryUserDto): Promise<string> {
    const { userName, phone, status, grade, province, city } = queryDto

    const queryBuilder = this.userRepository.createQueryBuilder('user')
      .where('user.is_delete = :isDelete', { isDelete: 0 })

    if (userName) {
      queryBuilder.andWhere('user.userName LIKE :userName', { userName: `%${userName}%` })
    }

    if (phone) {
      queryBuilder.andWhere('user.phone LIKE :phone', { phone: `%${phone}%` })
    }

    if (province) {
      queryBuilder.andWhere('user.province LIKE :province', { province: `%${province}%` })
    }

    if (city) {
      queryBuilder.andWhere('user.city LIKE :city', { city: `%${city}%` })
    }

    if (status) {
      queryBuilder.andWhere('user.status = :status', { status })
    }

    if (grade) {
      queryBuilder.andWhere('user.grade = :grade', { grade })
    }

    const users = await queryBuilder
      .orderBy('user.createdAt', 'DESC')
      .getMany()

    // 创建CSV格式
    const csvStringifier = createObjectCsvStringifier({
      header: [
        { id: 'userId', title: '用户ID' },
        { id: 'phone', title: '手机号' },
        { id: 'userName', title: '用户姓名' },
        { id: 'guarder', title: '监护人' },
        { id: 'guarderPhone', title: '监护人电话' },
        { id: 'guarderRelation', title: '与监护人关系' },
        { id: 'birthday', title: '出生日期' },
        { id: 'school', title: '学校' },
        { id: 'province', title: '省份' },
        { id: 'city', title: '城市' },
        { id: 'grade', title: '学级' },
        { id: 'from', title: '来源' },
        { id: 'status', title: '用户阶段' },
        { id: 'mark', title: '备注' },
        { id: 'createdAt', title: '创建时间' },
      ],
    })

    // 格式化数据
    const records = users.map(user => ({
      userId: user.userId,
      phone: user.phone,
      userName: user.userName,
      guarder: user.guarder,
      guarderPhone: user.guarderPhone,
      guarderRelation: user.guarderRelation,
      birthday: user.birthday ? user.birthday.toISOString().split('T')[0] : '',
      school: user.school,
      province: user.province,
      city: user.city,
      grade: user.grade,
      from: user.from,
      status: user.status,
      mark: user.mark,
      createdAt: user.createdAt?.toISOString().split('T')[0] || '',
    }))

    // 生成CSV字符串
    return csvStringifier.getHeaderString() + csvStringifier.stringifyRecords(records)
  }

  /**
   * 获取新的用户ID
   */
  async getNewUserId() {
    return this.generateUserId()
  }

  /**
   * 获取用户编辑历史记录
   */
  async getUserHistory(
    userId: number, 
    { page = 1, pageSize = 10 }
  ): Promise<{ items: CUserHistoryEntity[]; meta: any }> {
    const [items, total] = await this.userHistoryRepository.findAndCount({
      where: { userId },
      order: { createdAt: 'DESC' },
      skip: (page - 1) * pageSize,
      take: pageSize,
    })

    return {
      items,
      meta: {
        total,
        page,
        pageSize,
      },
    }
  }
}
